package su.myspringapps.onlineschool.repository;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import su.myspringapps.onlineschool.entity.Course;
import su.myspringapps.onlineschool.entity.Teacher;

import java.util.List;

import static org.hibernate.resource.transaction.spi.TransactionStatus.ACTIVE;
import static org.hibernate.resource.transaction.spi.TransactionStatus.MARKED_ROLLBACK;

/**
 * Класс CourseRepository реализует интерфейс {@link SimpleCrudRepository}
 * <p/>
 * Отвечает за работу с БД, связанную с сущностью {@link Course}
 * <p/>
 *
 * @author petr.mikhailin
 * created 21.05.2024 17:45
 */
@Repository
public class CourseRepository implements SimpleCrudRepository<Course, Integer> {

    private final TeacherRepository teacherRepository;

    private final SessionFactory sessionFactory;

    @Autowired
    public CourseRepository(TeacherRepository teacherRepository, SessionFactory sessionFactory) {
        this.teacherRepository = teacherRepository;
        this.sessionFactory = sessionFactory;
    }


    @Override
    public Integer create(Course entity) throws Exception {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            return (Integer) session.save(entity);
        } catch (Exception e) {
            if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
                transaction.rollback();
            }
            throw e;
        } finally {
            transaction.commit();
            session.close();
        }
    }

    @Override
    public void update(Course entity) throws Exception {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            session.update(entity);
        } catch (Exception e) {
            if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
                transaction.rollback();
            }
            throw e;
        } finally {
            transaction.commit();
            session.close();
        }
    }

    @Override
    public void delete(Course entity) throws Exception {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            session.delete(entity);
        } catch (Exception e) {
            if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
                transaction.rollback();
            }
            throw e;
        } finally {
            transaction.commit();
            session.close();
        }
    }

    @Override
    public Course findById(Integer id) throws Exception {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            return session.get(Course.class, id);
        } catch (Exception e) {
            if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
                transaction.rollback();
            }
            throw e;
        } finally {
            transaction.commit();
            session.close();
        }
    }

    @Override
    public List<Course> findAll() throws Exception {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            return session.createQuery("FROM Course", Course.class).list();
        } catch (Exception e) {
            if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
                transaction.rollback();
            }
            throw e;
        } finally {
            transaction.commit();
            session.close();
        }
    }

    public void assignTeacherToCourse(Teacher teacher, Course course) throws Exception {
        course.setTeacher(teacher);
        update(course);
    }

    public void unassignTeacherFromCourse(Teacher teacher, Course course) throws Exception {
        course.setTeacher(null);
        teacher.getCourses().remove(course);
        update(course);
        teacherRepository.update(teacher);
    }

}
